import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Date;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class EYIBCTest  {
	public static String getCurrentPath()
	{
		String sPath = new File("").getAbsolutePath() + '/';
		return sPath;
	}
	
	public static byte[] getBytesFromFile(File f) {
		if (f == null) {
			return null;
		}
		try {
			FileInputStream stream = new FileInputStream(f);
			ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
			byte[] b = new byte[1000];
			int n;
			while ((n = stream.read(b)) != -1)
				out.write(b, 0, n);
			stream.close();
			out.close();
			return out.toByteArray();
		} catch (IOException e) {
		}
		return null;
	}
	
	public static void getParamInfo(String fileName)
	{
		try {
		File paramFile = new File(fileName);
		           FileInputStream fis = new FileInputStream(paramFile);
		int temp = 0;
		byte[] paramContent = new byte[(int)paramFile.length()];
		while (true) {
			 temp = fis.read(paramContent);
			 if (temp == -1)
			  break;  
		}
		fis.close();
		byte[] domain = null;
		int[] version = null;
		
		    int paramContentSize = paramContent.length;
		    domain = new byte[256];
		    version = new int[1];
		    EYIBCLib eyibc = EYIBCLib.getInstance();
		    eyibc.getIBCParamInfo(paramContent,paramContentSize, domain, version);
		    System.out.println("domain: " + new String(domain) + " version + " + version[0]);
		}
		catch(FileNotFoundException e2){
		}
		catch (IOException e) {
		} 
		catch(EYIBCException eyEx) {
			eyEx.printStackTrace();
		}
	}
	
	public static String Bytes2HexString(byte[] b) { 
        String ret = ""; 
        for (int i = 0; i < b.length; i++) { 
            String hex = Integer.toHexString(b[i] & 0xFF); 
            if (hex.length() == 1) { 
                hex = '0' + hex; 
            } 
            ret += hex.toUpperCase(); 
        } 
        return ret; 
    }
    
	public static void TestSM2(){
		EYIBCLib eyibc = EYIBCLib.getInstance();
		
		long LibCtx;
		
		try {
			LibCtx = eyibc.createLibCtx();
			String password = "12345678";
			byte[] pubKeyBuf = new byte[128];
			byte[] prvKeyBuf = new byte[128];
			int[] pubKeyLen = new int[1];
			int[] prvKeyLen = new int[1];
			int pSize = 256;
			int nFormat = 1;
			eyibc.generateSM2KeyPair(password, pubKeyBuf, pubKeyLen, prvKeyBuf, prvKeyLen, pSize, nFormat);
			System.out.printf("generateSM2 pubKeyLen %d, prvKeyLen %d\n", pubKeyLen[0], prvKeyLen[0]);
			long pubkeyObject;
			long prvkeyObject;
			
			pubkeyObject = eyibc.createSM2PubKeyObjectFromMem(pubKeyBuf, pubKeyLen[0], 0);
			prvkeyObject = eyibc.createSM2PrvKeyObjectFromMem(LibCtx, prvKeyBuf, prvKeyLen[0], password, 0);
			
			String needCryptData = "abcdef";
			byte[] CryptedData = eyibc.cryptExportDataEx(pubkeyObject, needCryptData.getBytes());
			System.out.printf("cryptExportDataEx result length %d\n", CryptedData.length);
			byte[] OriData = eyibc.cryptImportData(prvkeyObject, CryptedData);
			System.out.printf("OriData is %s\n", new String(OriData));
			//对needCryptData 进行签名，需要先生成HASH对象
			long hashObject = eyibc.genHashObject(needCryptData.getBytes(), EYIBCAlg.ALG_HASH_SM3);
			byte[] SignedResult = eyibc.cryptSignDataEx(prvkeyObject, hashObject);
			
			int iResult = eyibc.cryptVerifySignDataEx(pubkeyObject, SignedResult, hashObject);
			System.out.printf("VerifySignData result %d\n", iResult);
			
			//释放对象
			eyibc.destroyHashObject(hashObject);
			eyibc.DestroyPrvKeyObject(prvkeyObject);
			eyibc.destroyPubKeyObject(pubkeyObject);
		} catch (EYIBCException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
		
	}
	
	public static void testEnc()
	{
		long IBCParamCtx = 0;
		try{
						
			EYIBCLib eyibc = EYIBCLib.getInstance();
			
			/*对称加密成P7文件
			String fileOld = getCurrentPath() + "/testfile/common.se";
			String fileNew = getCurrentPath() + "/testfile/common.enc";
			String fileOri = getCurrentPath() + "/testfile/common.ori";
			
			
			eyibc.P7CryptEncryptFile(EYIBCAlg.ALG_CIPHER_DES_CBC, "0123456789012345".getBytes(), 16, fileOld, fileNew);
			
			eyibc.P7CryptDecryptFile("0123456789012345".getBytes(), 16, fileNew, fileOri);
			*/
			
			//创建LibCtx;
			long LibCtx = eyibc.createLibCtx();
			getParamInfo(getCurrentPath() + "/testfile/common.se");
			
			//从内存中加载参数文件
			if (false)
			{
				try {
					File paramFile = new File(getCurrentPath() +"/testfile/common.se");
					FileInputStream fis = new FileInputStream(paramFile);
					int temp = 0;
					byte[] paramContent = new byte[(int)paramFile.length()];
					while (true) {
						temp = fis.read(paramContent);
						if (temp == -1)
						break;  
					}
					fis.close();
					byte[] domain = null;
					int[] version = null;
			
				int paramContentSize = paramContent.length;
				domain = new byte[256];
				version = new int[1];
			  
				IBCParamCtx = eyibc.loadIBCParamContentIntoLibCtx(LibCtx, paramContent, paramContent.length);
				if (EYIBCLib.isIBCError(IBCParamCtx))
				{
					//TODO ERROR
				}
				}
				catch(FileNotFoundException e2){
				}
				catch (IOException e) {
				} 
				catch(EYIBCException eyEx) {
					eyEx.printStackTrace();
					return;
				}
			}
			else
			{
				//加载参数文件
			  String sCommonFile = getCurrentPath() + "/testfile/common.se";
			  IBCParamCtx = eyibc.loadIBCParamIntoLibCtx(LibCtx, sCommonFile);
			}
		  
			//计算HASH，如SM3
			byte[] data = eyibc.genHashData("ooooo".getBytes(), EYIBCAlg.ALG_HASH_SM3);
			System.out.println("hash result: " + Bytes2HexString(data));

			//生成随机数
			byte[] random = new byte[20];
			eyibc.getRandom(random, 20);
			System.out.println("random result: " + Bytes2HexString(random));
		  
			//加载私钥文件
			String sPrivateFileName = getCurrentPath() + "/testfile/private.se";
			String sPrivatePassword = "123456";
			long IBCPrivateCtx = eyibc.createPrvKeyObjectFromFile(LibCtx, sPrivateFileName, sPrivatePassword);
			if (EYIBCLib.isIBCError(IBCPrivateCtx))
			{
				//TODO ERROR
			}
		  
			//读取私钥基本标识
			byte[] id = eyibc.getPrivateBasicID(IBCPrivateCtx);
			System.out.println("userid: " + new String(id));

			//读取私钥的参数域和版本号
			int[] version = new int[1];
			byte[] domain = eyibc.getPrivateDomainAndSerial(IBCPrivateCtx, version);
			System.out.println("domain: " + new String(domain) + "version: " + version[0]);

			//读取私钥的有效期
			long[] nBefore = new long[1];
			long[] nAfter = new long[1];
			eyibc.getPrivateValidTime(IBCPrivateCtx, nBefore, nAfter);
			System.out.println(" nAfter: " +  new Date(nAfter[0] * 1000));
			System.out.println(" nBefore: " +  new Date(nBefore[0] * 1000));
		  
			//对数据进行签名。
			String sNeedSigner = "good morning";
			byte[] signer = eyibc.cryptSignData(IBCPrivateCtx, sNeedSigner.getBytes());
			System.out.println("cryptSignData result: " + Bytes2HexString(signer));
			
			//对数据进行验签
			int result = eyibc.cryptVerifySignData(IBCParamCtx, signer, sNeedSigner.getBytes(), id);
	
			System.out.println("verifysign result: " + String.valueOf(result));

		
			
			//对数据进行非对称加密。
			String sNeedEncrypt = "good morning";
		
			String sID = new String(id);
			byte[] encryptedData = eyibc.cryptExportData(IBCParamCtx, 0, sID, sNeedEncrypt.getBytes());
			
			System.out.println("encrypted size: " + encryptedData.length);
			//对数据进行非对称解密

			byte[] decryptedData = eyibc.cryptImportData(IBCPrivateCtx, encryptedData);
			System.out.println("decrypt right: " + new String(decryptedData));
					
			//对数据进行对称加密  //对称加密算法，如果用EYIBCAlg.ALG_CIPHER_DES_CBC等, SM4密码请用16位
			String sPassword = "1234567890123456";
			String sOldData = "4341324124132";
			byte[] encryptedData1 = eyibc.cryptEncrypt(EYIBCAlg.ALG_CIPHER_SM4_CBC, sPassword.getBytes(), null, sOldData.getBytes(), 0);

			//对数据进行对称解密
			byte[] decryptedData1 = eyibc.cryptDecrypt(EYIBCAlg.ALG_CIPHER_SM4_CBC, sPassword.getBytes(), null, encryptedData1, 0);
			System.out.println("cryptDecrypt right: " + new String(decryptedData1));

			
		} catch(Exception ex){
			System.out.println("error");
			System.out.println(ex.getMessage());
			ex.printStackTrace();
		}
	}
	
	public static void TestXC()
	{
		EYIBCLib eyibc = EYIBCLib.getInstance();
		eyibc.initEYIBC();
		eyibc.SetEYIBCIntConfig(3, 1);
		int cType = 7;
		int iPsize = 256;
		int iRsize = 256;
		String masterPassword = "12345678";

		String mkfile = "d:\\master1.prv";
		String paramfile = "d:\\master1.com";
		try
		{
			//生成主密钥
			eyibc.GMIBCSSG("domainname", 1, EYIBCAlg.TYPE7CURVE, iPsize, iRsize, 
			EYIBCAlg.ALG_IBC_KGA_CHN_H2R3_SHA1, EYIBCAlg.GM_ID_SCHEMA_CHNSCHEMA, paramfile , mkfile, masterPassword);
			
			//加载主密钥及其参数
			long masterkeyCtx = eyibc.IBCLoadMasterKeyFromFile(mkfile, masterPassword);
			long paramCtx = eyibc.CreateIBCParamObjectFromFile(paramfile);
			
			//短签名
			String needSign = "helloworld";
			byte[] signed = eyibc.GMIBCSSS(masterkeyCtx, paramCtx, needSign.getBytes(), needSign.getBytes().length);
			
			//短验签
			eyibc.GMIBCSSV(paramCtx, needSign.getBytes(), needSign.getBytes().length, signed, signed.length);
			
			String accountID = "abcdefg";
			//短加密
			byte[] encdata = eyibc.GMCHNIBEEncEx(paramCtx, 0, accountID, needSign.getBytes(), needSign.getBytes().length);
			//短解密
			byte[] ori = eyibc.GMCHNIBEDecExFromMaster(masterkeyCtx, paramCtx, 0, accountID, "d:\\tmp.file", encdata, encdata.length);
			System.out.println("ori " + new String(ori));
		} catch(Exception ex){
			System.out.println("error");
			System.out.println(ex.getMessage());
			ex.printStackTrace();
		}
	}
	
	public static void getFile(byte[] bfile, String filePath,String fileName) {  
        BufferedOutputStream bos = null;  
        FileOutputStream fos = null;  
        File file = null;  
        try {  
            File dir = new File(filePath);  
            if(!dir.exists()&&dir.isDirectory()){//判断文件目录是否存在  
                dir.mkdirs();  
            }  
            file = new File(filePath+"\\"+fileName);  
            fos = new FileOutputStream(file);  
            bos = new BufferedOutputStream(fos);  
            bos.write(bfile);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (bos != null) {  
                try {  
                    bos.close();  
                } catch (IOException e1) {  
                    e1.printStackTrace();  
                }  
            }  
            if (fos != null) {  
                try {  
                    fos.close();  
                } catch (IOException e1) {  
                    e1.printStackTrace();  
                }  
            }  
        }  
	}
	
	public static void TestLocalEnc(){
		long LibCtx;
		EYIBCLib eyibc = EYIBCLib.getInstance();
		eyibc.initEYIBC();
		
		try {
			LibCtx = eyibc.createLibCtx();
			
			long paramObject = eyibc.loadIBCParamIntoLibCtx(LibCtx, "d:\\common.se");
			
			String needEnc = "helloworld";
			byte[] encData = eyibc.P7Write(LibCtx, paramObject, "demo@olymtech.net", 0, needEnc.getBytes(), needEnc.getBytes().length);
			
			//save to file to test
			getFile(encData, "d:\\", "test.p7");
			
			eyibc.DestroyIBCParamObject(paramObject);
			eyibc.DestroyLibCtx(LibCtx);
		} catch (EYIBCException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void TestCTR()
	{
		EYIBCLib eyibc = EYIBCLib.getInstance();
		int nAlg = EYIBCAlg.ALG_CIPHER_SM4_CTR;
		
		boolean bDataMatch = true;
		//为了测试，此处需要加密的内容、IV、KEY都是随机临时生成
		byte[] needEncData = new byte[1025];
		byte[] iv = new byte[16]; 	
		byte[] key = new byte[16];		
		try {
			for(int i=0; i<needEncData.length; i++)
			{
				needEncData[i] = (byte)i;
			}
					
			eyibc.getRandom(iv, iv.length);	
			eyibc.getRandom(key, key.length);
			
			//测试，一次性加密所有的数据
			byte[] encData = eyibc.GMCryptEncryptCTR(key, key.length, iv, iv.length, needEncData, needEncData.length, nAlg, 0);
			
			//测试，一次性解密所有的数据
			byte[] oriData = eyibc.GMCryptDecryptCTR(key, key.length, iv, iv.length, encData, encData.length, nAlg, 0);
			
			
			bDataMatch = true;
			//比较数据
			if (oriData.length == needEncData.length)
			{
				for(int i=0; i<oriData.length; i++)
				{
					if (oriData[i] != needEncData[i])
					{
						bDataMatch = false;
						break;
					}
				}
			}
			else
				bDataMatch = false;
			
			if (bDataMatch)
				System.out.println("数据相同");
			else
				System.out.println("数据不同");
			//测试，解密中间一段数据，从257 开始的33个字节
			int offset = 257;
			byte[] middleData = new byte[33];
			System.arraycopy(encData, 257, middleData, 0, 33);
			
			byte[] oriDataMid = eyibc.GMCryptDecryptCTR(key, key.length, iv, iv.length, middleData, middleData.length, nAlg, offset);
			
			//比较数据
			bDataMatch = true;
			for (int i=0; i<oriDataMid.length; i++)
			{
				if (needEncData[i + offset] != oriDataMid[i])
				{
					bDataMatch = false;
					break;
				}
			}
			
			if (bDataMatch)
				System.out.println("数据相同");
			else
				System.out.println("数据不同");
		} catch (EYIBCException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	public static void main(String[] args) {
		System.out.println(System.getProperty("java.library.path"));
		//testEnc();
		TestCTR();
		//TestXC();
	}
	
	public native int SM2VerifyFile(String CheckFile, String Sm2File);
}
